"""
文件处理服务模块
负责文件上传、内容提取和预处理
"""

import os
import io
import logging
import mimetypes
import tempfile
from pathlib import Path
from typing import Dict, Any, Optional, List
from fastapi import UploadFile

from ..core.config import settings

logger = logging.getLogger(__name__)

# 导入基础依赖
try:
    import html2text
    import langdetect
    HAS_BASIC_DEPS = True
except ImportError as e:
    HAS_BASIC_DEPS = False
    logger.warning(f"基础文档处理依赖未安装: {e}")

# 导入Docling
try:
    from docling.document_converter import DocumentConverter, PdfFormatOption
    from docling.datamodel.base_models import InputFormat
    from docling.datamodel.pipeline_options import PdfPipelineOptions
    HAS_DOCLING = True
    logger.info("Docling已成功导入")
except ImportError as e:
    HAS_DOCLING = False
    logger.warning(f"Docling未安装: {e}")
    raise ImportError("Docling是必需的依赖，请安装: pip install docling")


class FileService:
    """文件处理服务类"""
    
    def __init__(self):
        self.allowed_extensions = {
            '.txt', '.pdf', '.doc', '.docx', '.xls', '.xlsx', 
            '.ppt', '.pptx', '.md', '.html'
        }
        self.max_file_size = settings.MAX_FILE_SIZE
        self.upload_dir = settings.UPLOAD_DIR
        
        # 确保上传目录存在
        os.makedirs(self.upload_dir, exist_ok=True)
        
        # 初始化Docling转换器
        try:
            # 配置PDF处理选项
            pipeline_options = PdfPipelineOptions()
            pipeline_options.do_ocr = True  # 启用OCR
            pipeline_options.do_table_structure = True  # 启用表格结构识别
            
            # 创建文档转换器，使用新的API
            self.docling_converter = DocumentConverter(
                format_options={
                    InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
                }
            )
            logger.info("Docling转换器初始化成功")
        except Exception as e:
            logger.error(f"Docling转换器初始化失败: {e}")
            raise RuntimeError(f"无法初始化Docling转换器: {e}")
    
    def validate_file(self, file: UploadFile) -> Dict[str, Any]:
        """验证上传的文件"""
        if not file.filename:
            return {"valid": False, "error": "文件名不能为空"}
        
        # 检查文件扩展名
        file_ext = Path(file.filename).suffix.lower()
        if file_ext not in self.allowed_extensions:
            return {
                "valid": False, 
                "error": f"不支持的文件类型: {file_ext}。支持的类型: {', '.join(self.allowed_extensions)}"
            }
        
        # 检查文件大小
        if hasattr(file, 'size') and file.size > self.max_file_size:
            return {
                "valid": False, 
                "error": f"文件大小超过限制 ({self.max_file_size / 1024 / 1024:.1f}MB)"
            }
        
        return {"valid": True}
    
    async def save_file(self, file: UploadFile) -> Dict[str, Any]:
        """保存上传的文件"""
        try:
            logger.info(f"📁 开始保存上传文件: {file.filename}, 大小: {file.size if hasattr(file, 'size') else '未知'}")
            
            # 生成安全的文件名
            safe_filename = self._generate_safe_filename(file.filename)
            file_path = os.path.join(self.upload_dir, safe_filename)
            logger.info(f"📁 生成安全文件名: {safe_filename}, 保存路径: {file_path}")
            
            # 保存文件
            content = await file.read()
            with open(file_path, "wb") as f:
                f.write(content)
            
            logger.info(f"✅ 文件保存成功: {safe_filename}, 实际大小: {len(content)} bytes")
            
            return {
                "success": True,
                "file_path": file_path,
                "filename": safe_filename,
                "size": len(content)
            }
        except Exception as e:
            logger.error(f"❌ 保存文件失败: {str(e)}")
            return {"success": False, "error": str(e)}
    
    def extract_content(self, file_path: str) -> Dict[str, Any]:
        """提取文件内容"""
        try:
            file_ext = Path(file_path).suffix.lower()
            logger.info(f"🔍 开始提取文件内容: {file_path}, 文件类型: {file_ext}")
            
            # 使用Docling处理支持的文档格式
            if file_ext in ['.pdf', '.docx', '.doc', '.pptx', '.ppt']:
                logger.info(f"📄 使用Docling处理文档: {file_ext}")
                return self._extract_with_docling(file_path)
            
            # 处理其他格式
            if file_ext == '.txt':
                logger.info(f"📝 处理文本文件: {file_ext}")
                return self._extract_text_file(file_path)
            elif file_ext in ['.xls', '.xlsx']:
                logger.info(f"📊 处理Excel文件: {file_ext}")
                return self._extract_excel_content(file_path)
            elif file_ext == '.md':
                logger.info(f"📋 处理Markdown文件: {file_ext}")
                return self._extract_markdown_content(file_path)
            elif file_ext == '.html':
                logger.info(f"🌐 处理HTML文件: {file_ext}")
                return self._extract_html_content(file_path)
            else:
                logger.warning(f"❌ 不支持的文件类型: {file_ext}")
                return {
                    "success": False,
                    "error": f"不支持的文件类型: {file_ext}。支持的格式：PDF, Word, PowerPoint, Excel, 文本, Markdown, HTML"
                }
        except Exception as e:
            logger.error(f"❌ 提取文件内容失败: {str(e)}")
            return {"success": False, "error": str(e)}
    
    def _generate_safe_filename(self, filename: str) -> str:
        """生成安全的文件名"""
        import uuid
        import time
        
        # 获取文件扩展名
        file_ext = Path(filename).suffix.lower()
        
        # 生成唯一文件名
        timestamp = str(int(time.time()))
        unique_id = str(uuid.uuid4())[:8]
        safe_name = f"{timestamp}_{unique_id}{file_ext}"
        
        return safe_name
    
    def _extract_with_docling(self, file_path: str) -> Dict[str, Any]:
        """使用Docling提取文档内容"""
        try:
            logger.info(f"🚀 开始使用Docling转换文档: {file_path}")
            
            # 使用Docling转换文档
            logger.info(f"📡 调用Docling转换器...")
            result = self.docling_converter.convert(file_path)
            logger.info(f"✅ Docling转换完成")
            
            # 提取文本内容
            logger.info(f"📝 导出Markdown格式内容...")
            content = result.document.export_to_markdown()
            logger.info(f"✅ 内容导出完成，长度: {len(content)} 字符")
            
            # 获取文件类型
            file_ext = Path(file_path).suffix.lower()
            file_type_map = {
                '.pdf': 'pdf',
                '.doc': 'word',
                '.docx': 'word', 
                '.ppt': 'powerpoint',
                '.pptx': 'powerpoint'
            }
            
            # 收集元数据
            pages_count = len(result.document.pages) if hasattr(result.document, 'pages') else None
            tables_count = len([item for item in result.document.items if item.prov and 'table' in item.prov.get('category', '')]) if hasattr(result.document, 'items') else 0
            images_count = len([item for item in result.document.items if item.prov and 'picture' in item.prov.get('category', '')]) if hasattr(result.document, 'items') else 0
            
            logger.info(f"📊 文档元数据 - 页数: {pages_count}, 表格: {tables_count}, 图片: {images_count}")
            
            # 检测语言
            language = self._detect_language(content)
            logger.info(f"🌐 检测到语言: {language}")
            
            result_data = {
                "success": True,
                "content": content,
                "file_type": file_type_map.get(file_ext, "document"),
                "language": language,
                "used_docling": True,
                "metadata": {
                    "pages": pages_count,
                    "tables": tables_count,
                    "images": images_count
                }
            }
            
            logger.info(f"🎉 Docling处理成功完成！")
            return result_data
            
        except Exception as e:
            logger.error(f"❌ Docling文档提取失败: {str(e)}")
            logger.error(f"❌ 错误详情: {type(e).__name__}: {e}")
            import traceback
            logger.error(f"❌ 完整错误堆栈:\n{traceback.format_exc()}")
            return {"success": False, "error": f"文档处理失败: {str(e)}"}
    
    def _extract_text_file(self, file_path: str) -> Dict[str, Any]:
        """提取文本文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            return {
                "success": True,
                "content": content,
                "file_type": "text",
                "language": self._detect_language(content)
            }
        except UnicodeDecodeError:
            # 尝试其他编码
            for encoding in ['gbk', 'gb2312', 'latin1']:
                try:
                    with open(file_path, 'r', encoding=encoding) as f:
                        content = f.read()
                    return {
                        "success": True,
                        "content": content,
                        "file_type": "text",
                        "language": self._detect_language(content)
                    }
                except UnicodeDecodeError:
                    continue
            
            return {"success": False, "error": "无法解码文件内容"}
    

    
    def _extract_excel_content(self, file_path: str) -> Dict[str, Any]:
        """提取Excel文件内容"""
        try:
            import pandas as pd
            df = pd.read_excel(file_path, sheet_name=None)
            content = ""
            
            for sheet_name, sheet_data in df.items():
                content += f"工作表: {sheet_name}\n"
                content += sheet_data.to_string() + "\n\n"
            
            return {
                "success": True,
                "content": content,
                "file_type": "excel",
                "language": self._detect_language(content)
            }
        except ImportError:
            return {"success": False, "error": "pandas依赖未安装，无法处理Excel文件"}
        except Exception as e:
            logger.error(f"Excel内容提取失败: {str(e)}")
            return {"success": False, "error": str(e)}
    
    def _extract_markdown_content(self, file_path: str) -> Dict[str, Any]:
        """提取Markdown文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            return {
                "success": True,
                "content": content,
                "file_type": "markdown",
                "language": self._detect_language(content)
            }
        except Exception as e:
            logger.error(f"Markdown内容提取失败: {str(e)}")
            return {"success": False, "error": str(e)}
    
    def _extract_html_content(self, file_path: str) -> Dict[str, Any]:
        """提取HTML文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                html_content = f.read()
            
            # 转换HTML为纯文本
            if HAS_BASIC_DEPS:
                h = html2text.HTML2Text()
                h.ignore_links = True
                content = h.handle(html_content)
            else:
                # 简单的HTML标签移除
                import re
                content = re.sub(r'<[^>]+>', '', html_content)
            
            return {
                "success": True,
                "content": content,
                "file_type": "html",
                "language": self._detect_language(content)
            }
        except Exception as e:
            logger.error(f"HTML内容提取失败: {str(e)}")
            return {"success": False, "error": str(e)}
    

    
    def _detect_language(self, text: str) -> str:
        """检测文本语言"""
        if not HAS_BASIC_DEPS or not text.strip():
            return "unknown"
        
        try:
            return langdetect.detect(text)
        except:
            return "unknown"
    
    def cleanup_file(self, file_path: str) -> bool:
        """清理临时文件"""
        try:
            if os.path.exists(file_path):
                os.remove(file_path)
            return True
        except Exception as e:
            logger.error(f"清理文件失败: {str(e)}")
            return False


# 创建全局文件服务实例
file_service = FileService() 